package cc.kzc.adminauth.auth.tool;

import java.time.Instant;
import java.util.Date;
import java.util.Map;
import java.util.Objects;
import java.util.UUID;

import javax.crypto.SecretKey;

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jws;
import io.jsonwebtoken.JwsHeader;
import io.jsonwebtoken.JwtBuilder;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.lang.Arrays;
import io.jsonwebtoken.security.SecureDigestAlgorithm;

public class SymmJwtUtil {

	/**
	 * 加密算法
	 */
	private final static SecureDigestAlgorithm<SecretKey, SecretKey> ALGORITHM = Jwts.SIG.HS256;

	/**
	 * jwt签发者。服务本身。
	 */
	private final static String JWT_ISS = "szskycity.com";

	// 计算从1970-01-01到2024-01-01的毫秒数
	private final static long MILLIS_SINCE_EPOCH = 1704067200000L; // 请注意，这个值是预计算好的，对应于2024-01-01T00:00:00Z
	public final static Date DATE_2024 = new Date(MILLIS_SINCE_EPOCH);

	/**
	 * 这些是一组预定义的声明，它们不是强制性的，而是推荐的，以提供一组有用的、可互操作的声明 。
	 * 
	 * <pre>
	 * iss: jwt签发者。
	 * sub: jwt所面向的用户，用户ID。
	 * aud: 接收jwt的主体/服务，一般是颁发给某个可信的APP。使用AppID或者ClientID。
	 * exp: jwt的过期时间，这个过期时间必须要大于签发时间。
	 * nbf: 定义在什么时间之前，该jwt都是不可用的。
	 * iat: jwt的签发时间。
	 * jti: jwt的唯一身份标识，主要用来作为一次性token,从而回避重放攻击。
	 * </pre>
	 * 
	 * @param secretKey
	 * @param uid
	 * @param appid
	 * @param extClaims
	 * @param expire
	 * @return
	 * 
	 */
	public static String genToken(SecretKey secretKey, String uid, String[] appids, Map<String, Object> extClaims,
			long expire) {
		Objects.requireNonNull(secretKey);
		// 令牌id
		String jtiUuid = UUID.randomUUID().toString();
		Date exprireDate = Date.from(Instant.now().plusSeconds(0 < expire ? expire : 0));

		JwtBuilder jwtBuilder = Jwts.builder();
		/**
		 * 设置头部信息header
		 */
		jwtBuilder.header().add("typ", "JWT").add("alg", "HS256").and();
		/**
		 * 设置负载信息payload
		 */
		jwtBuilder
				// 签发者
				.issuer(JWT_ISS)
				// 主题
				.subject(uid)
				// 受众，即预期接收并处理此令牌的服务
				.audience().add(Arrays.asList(appids)).and()
				// 签发时间
				.issuedAt(new Date())
				// 2024年之前无效
				.notBefore(DATE_2024)
				// 过期日期
				.expiration(exprireDate)
				// jti令牌ID
				.id(jtiUuid);
		/**
		 * 设置负载信息"附加"payload
		 */
		if (null != extClaims && 0 < extClaims.size()) {
			// 设置自定义信息
			jwtBuilder.claims(extClaims);
		}
		/**
		 * 签名
		 */
		jwtBuilder.signWith(secretKey, ALGORITHM);
		return jwtBuilder.compact();
	}

	/**
	 * 解析token
	 * 
	 * @param token token
	 * @return Jws<Claims>
	 */
	public static Jws<Claims> parseClaim(SecretKey secretKey, String token) {
		return Jwts.parser().verifyWith(secretKey).build().parseSignedClaims(token);
	}

	public static JwsHeader parseHeader(SecretKey secretKey, String token) {
		return parseClaim(secretKey, token).getHeader();
	}

	public static Claims parsePayload(SecretKey secretKey, String token) {
		return parseClaim(secretKey, token).getPayload();
	}

}
